package cn.com.cetccst.location;

import android.content.Context;
import android.os.PowerManager;
import android.util.Log;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;

import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
import cn.com.cetccst.kvmanager.IKVStore;

import org.slf4j.Logger;

import java.util.ArrayList;
import java.util.List;

import cn.com.cetccst.datacenter.collection.entity.LocationRecordEntity;
import cn.com.cetccst.location.peroid.PeroidLocateHelper;

public class LocationService {

    private static final String TAG = "LocationService";

    private Context mContext;
    private GeoFenceManager mGeoFenceManager;
    private PeroidLocateHelper mPeroidLocateHelper;
    private AMapLocationClient mLocationClient = null;
    private AMapLocationClientOption mOption;
    private final static Object sLock = new Object();
    private LocationRecordEntity mLastLocation;
    private List<LocationListener> mLocationListeners = new ArrayList<>();
    private final MutableLiveData<LocationRecordEntity> mLocationRecordLiveData = new MutableLiveData<>();
    public static IKVStore sKVStore;
    public static Logger sLogger;

    private static class SingletonHolder {
        private static final LocationService INSTANCE = new LocationService();
    }

    public static LocationService getInstance() {
        return SingletonHolder.INSTANCE;
    }

    // 私有构造函数
    private LocationService() {
    }

    public static void setKVStore(IKVStore kvStore) {
        sKVStore = kvStore;
    }

    public static void setLogger(Logger logger) {
        sLogger = logger;
    }

    public void initialize(Context context) {
        synchronized (sLock) {
            if (mLocationClient == null) {
                try {
                    mContext = context;

                    AMapLocationClient.updatePrivacyShow(context, true, true);
                    AMapLocationClient.updatePrivacyAgree(context, true);
                    mGeoFenceManager = new GeoFenceManager(context);
                    mLocationClient = new AMapLocationClient(context);
                    mLocationClient.setLocationOption(getDefaultLocationClientOption());
                    mLocationClient.setLocationListener(new AMapLocationListener() {
                        @Override
                        public void onLocationChanged(AMapLocation aMapLocation) {
                            String locationStr = aMapLocation.getLongitude() + "," + aMapLocation.getLatitude() + "," + aMapLocation.getAddress() + "," + aMapLocation.getProvider() + "," + aMapLocation.getAccuracy() + "," + aMapLocation.getLocationType();
                            Log.i(TAG, "received location: " + locationStr);
                            stop();
                            cacheLocation(aMapLocation);
                        }
                    });
                    start();
                    mPeroidLocateHelper = new PeroidLocateHelper(mContext);

                } catch (Exception e) {
                    e.printStackTrace();
                }

            }
        }
    }

    public AMapLocationClientOption getDefaultLocationClientOption() {
        if (mOption == null) {
            mOption = new AMapLocationClientOption();
            mOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);//可选，设置定位模式，可选的模式有高精度、仅设备、仅网络。默认为高精度模式
            mOption.setGpsFirst(false);//可选，设置是否gps优先，只在高精度模式下有效。默认关闭
            //现在定位是单次定位，再这设置超时30s感觉没有什么意义，而且目前定位等待8s，还会导致时间内没有结果返回。
            //修改为小于8s
            mOption.setHttpTimeOut(7500);//可选，设置网络请求超时时间。默认为30秒。在仅设备模式下无效
            mOption.setInterval(2000);//可选，设置定位间隔。默认为2秒
            mOption.setNeedAddress(true);//可选，设置是否返回逆地理地址信息。默认是true
            mOption.setOnceLocation(true);//可选，设置是否单次定位。默认是false
            mOption.setOnceLocationLatest(true);//可选，设置是否等待wifi刷新，默认为false.如果设置为true,\

            // 会自动变为单次定位，持续定位时不要使用
            mOption.setSensorEnable(false);//可选，设置是否使用传感器。默认是false
            mOption.setWifiScan(true); //可选，设置是否开启wifi扫描。默认为true，如果设置为false会同时停止主动刷新，停止以后完全依赖于系统刷新，定位位置可能存在误差
            mOption.setLocationCacheEnable(true); //可选，设置是否使用缓存定位，默认为true
            mOption.setGeoLanguage(AMapLocationClientOption.GeoLanguage.DEFAULT);//可选，设置逆地理信息的语言，默认值为默认语言（根据所在地区选择语言）
        }
        return mOption;
    }

    public GeoFenceManager getGeoFenceManager() {
        return mGeoFenceManager;
    }

    public PeroidLocateHelper getPeroidLocateHelper() {
        return mPeroidLocateHelper;
    }

    public void addLocationListener(LocationListener locationListener) {
        mLocationListeners.add(locationListener);
    }

    public void removeLocationListener(LocationListener locationListener) {
        mLocationListeners.remove(locationListener);
    }

    private void notifyLocationChanged() {
        mLocationRecordLiveData.setValue(mLastLocation);
        for (LocationListener listener : mLocationListeners) {
            listener.onLocationChanged(mLastLocation);
        }
    }

    public void start() {
        if (mLocationClient == null) {
            Log.e(TAG, "location client not initialized");
            return;
        }
        wakeLock();
        synchronized (sLock) {
            if (mLocationClient != null) {
                mLocationClient.startLocation();
                Log.i(TAG, "start location track");
            }
        }
    }

    public void stop() {
        synchronized (sLock) {
            if (mLocationClient != null) {
                mLocationClient.stopLocation();
                Log.i(TAG, "location track has been stopped.");
            }
        }
    }

    public LocationRecordEntity getLastLocation() {
        return mLastLocation;
    }

    public LiveData<LocationRecordEntity> getLocationRecordLiveData() {
        return mLocationRecordLiveData;
    }

    public void cacheLocation(AMapLocation aMapLocation) {
        LocationRecordEntity entity = new LocationRecordEntity();
        entity.setLatitude(aMapLocation.getLatitude());
        entity.setLongitude(aMapLocation.getLongitude());
        entity.setAddress(aMapLocation.getAddress());
        //https://lbs.amap.com/api/android-location-sdk/guide/utilities/location-type
        //11|模糊定位结果|模糊定位权限，当用户设置应用定位权限为“大致位置”时，返回用户大致位置
        entity.setAccurate(aMapLocation.getLocationType() != 11);
        boolean success = LocationUtil.isValidLocation(aMapLocation.getLatitude(), aMapLocation.getLongitude()) && aMapLocation.getErrorCode() == 0;
        entity.setSuccess(success);

        if (!success) {
            List<Integer> codes = new ArrayList<>();
            if (!LocationUtil.isLocationServiceEnabled(mContext)) {
                codes.add(1);
            }
            if (!LocationUtil.isAlwaysPermissionGranted(mContext)) {
                codes.add(2);
            }
            if (!LocationUtil.isFlightModeEnabled(mContext)) {
                codes.add(3);
            }
            //定位失败，而且具体原因不是上面的三个时统一返回0.
            if (codes.isEmpty()) {
                codes.add(0);
            }
            entity.setErrorCodes(codes);
        }
        entity.setLocateTime(System.currentTimeMillis());
        mLastLocation = entity;
        notifyLocationChanged();
    }

    //休眠后会导致 1.定位不到；2.获取定位服务开关错误，所以在定位之前尝试调用一下
    public void wakeLock() {
        try {
            if (mContext == null) {
                Log.i(TAG, "cannot wakelock due context is null");
                return;
            }
            PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
            PowerManager.WakeLock wakeLock = pm.newWakeLock((PowerManager.SCREEN_BRIGHT_WAKE_LOCK
                    | PowerManager.ACQUIRE_CAUSES_WAKEUP), "emmlocation:");
            wakeLock.acquire(100);
            Thread.sleep(100);
            wakeLock.release();
        } catch (Exception e) {
            Log.i(TAG, "wakeLock Exception ", e);
        }
    }
}
